x86: Allow direct vectored interrupts to be dynamically allocated.
authorKeir Fraser <keir@xen.org>
Fri, 30 Mar 2012 08:14:25 +0000 (09:14 +0100)
committerKeir Fraser <keir@xen.org>
Fri, 30 Mar 2012 08:14:25 +0000 (09:14 +0100)
Use this for Intel's CMCI and thermal interrupts.

Signed-off-by: Keir Fraser <keir@xen.org>
xen/arch/x86/apic.c
xen/arch/x86/cpu/mcheck/mce_intel.c
xen/arch/x86/irq.c
xen/include/asm-x86/irq.h
xen/include/asm-x86/mach-default/irq_vectors.h

index cde3cd5dfcc4807637c4554774ec22149579ded4..e05dd82bb24c79f60694e1bd610dc775eb445ce5 100644 (file)
@@ -128,14 +128,6 @@ void __init apic_intr_init(void)
 
     /* Performance Counters Interrupt */
     set_direct_apic_vector(PMU_APIC_VECTOR, pmu_apic_interrupt);
-
-    /* CMCI Correctable Machine Check Interrupt */
-    set_direct_apic_vector(CMCI_APIC_VECTOR, cmci_interrupt);
-
-    /* thermal monitor LVT interrupt, for P4 and latest Intel CPU*/
-#ifdef CONFIG_X86_MCE_THERMAL
-    set_direct_apic_vector(THERMAL_APIC_VECTOR, thermal_interrupt);
-#endif
 }
 
 /* Using APIC to generate smp_local_timer_interrupt? */
index e2eed836d55c7ea47e89e58635a64368f07ae885..2d6c2f53077c95425bd23d53f91807f9d9b331f1 100644 (file)
@@ -46,22 +46,15 @@ static int __read_mostly nr_intel_ext_msrs;
 #define INTEL_SRAR_DATA_LOAD   0x134
 #define INTEL_SRAR_INSTR_FETCH 0x150
 
-/* Thermal Hanlding */
 #ifdef CONFIG_X86_MCE_THERMAL
-static void unexpected_thermal_interrupt(struct cpu_user_regs *regs)
-{
-    printk(KERN_ERR "Thermal: CPU%d: Unexpected LVT TMR interrupt!\n",
-                smp_processor_id());
-    add_taint(TAINT_MACHINE_CHECK);
-}
-
-/* P4/Xeon Thermal transition interrupt handler */
 static void intel_thermal_interrupt(struct cpu_user_regs *regs)
 {
     uint64_t msr_content;
     unsigned int cpu = smp_processor_id();
     static DEFINE_PER_CPU(s_time_t, next);
 
+    ack_APIC_irq();
+
     if (NOW() < per_cpu(next, cpu))
         return;
 
@@ -77,16 +70,6 @@ static void intel_thermal_interrupt(struct cpu_user_regs *regs)
     }
 }
 
-/* Thermal interrupt handler for this CPU setup */
-static void (*__read_mostly vendor_thermal_interrupt)(
-    struct cpu_user_regs *regs) = unexpected_thermal_interrupt;
-
-void thermal_interrupt(struct cpu_user_regs *regs)
-{
-    ack_APIC_irq();
-    vendor_thermal_interrupt(regs);
-}
-
 /* Thermal monitoring depends on APIC, ACPI and clock modulation */
 static int intel_thermal_supported(struct cpuinfo_x86 *c)
 {
@@ -117,6 +100,7 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
     uint32_t val;
     int tm2 = 0;
     unsigned int cpu = smp_processor_id();
+    static uint8_t thermal_apic_vector;
 
     if (!intel_thermal_supported(c))
         return; /* -ENODEV */
@@ -159,17 +143,16 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
         return; /* -EBUSY */
     }
 
+    alloc_direct_apic_vector(&thermal_apic_vector, intel_thermal_interrupt);
+
     /* The temperature transition interrupt handler setup */
-    val = THERMAL_APIC_VECTOR;    /* our delivery vector */
+    val = thermal_apic_vector;    /* our delivery vector */
     val |= (APIC_DM_FIXED | APIC_LVT_MASKED);  /* we'll mask till we're ready */
     apic_write_around(APIC_LVTTHMR, val);
 
     rdmsrl(MSR_IA32_THERM_INTERRUPT, msr_content);
     wrmsrl(MSR_IA32_THERM_INTERRUPT, msr_content | 0x03);
 
-    /* ok we're good to go... */
-    vendor_thermal_interrupt = intel_thermal_interrupt;
-
     rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
     wrmsrl(MSR_IA32_MISC_ENABLE, msr_content | (1ULL<<3));
 
@@ -1154,10 +1137,34 @@ static void cpu_mcheck_disable(void)
         clear_cmci();
 }
 
+static void cmci_interrupt(struct cpu_user_regs *regs)
+{
+    mctelem_cookie_t mctc;
+    struct mca_summary bs;
+
+    ack_APIC_irq();
+
+    mctc = mcheck_mca_logout(
+        MCA_CMCI_HANDLER, __get_cpu_var(mce_banks_owned), &bs, NULL);
+
+    if (bs.errcnt && mctc != NULL) {
+        if (dom0_vmce_enabled()) {
+            mctelem_commit(mctc);
+            mce_printk(MCE_VERBOSE, "CMCI: send CMCI to DOM0 through virq\n");
+            send_global_virq(VIRQ_MCA);
+        } else {
+            x86_mcinfo_dump(mctelem_dataptr(mctc));
+            mctelem_dismiss(mctc);
+       }
+    } else if (mctc != NULL)
+        mctelem_dismiss(mctc);
+}
+
 static void intel_init_cmci(struct cpuinfo_x86 *c)
 {
     u32 l, apic;
     int cpu = smp_processor_id();
+    static uint8_t cmci_apic_vector;
 
     if (!mce_available(c) || !cmci_support) {
         if (opt_cpu_info)
@@ -1173,7 +1180,9 @@ static void intel_init_cmci(struct cpuinfo_x86 *c)
         return;
     }
 
-    apic = CMCI_APIC_VECTOR;
+    alloc_direct_apic_vector(&cmci_apic_vector, cmci_interrupt);
+
+    apic = cmci_apic_vector;
     apic |= (APIC_DM_FIXED | APIC_LVT_MASKED);
     apic_write_around(APIC_CMCI, apic);
 
@@ -1183,29 +1192,6 @@ static void intel_init_cmci(struct cpuinfo_x86 *c)
     mce_set_owner();
 }
 
-void cmci_interrupt(struct cpu_user_regs *regs)
-{
-    mctelem_cookie_t mctc;
-    struct mca_summary bs;
-
-    ack_APIC_irq();
-
-    mctc = mcheck_mca_logout(
-        MCA_CMCI_HANDLER, __get_cpu_var(mce_banks_owned), &bs, NULL);
-
-    if (bs.errcnt && mctc != NULL) {
-        if (dom0_vmce_enabled()) {
-            mctelem_commit(mctc);
-            mce_printk(MCE_VERBOSE, "CMCI: send CMCI to DOM0 through virq\n");
-            send_global_virq(VIRQ_MCA);
-        } else {
-            x86_mcinfo_dump(mctelem_dataptr(mctc));
-            mctelem_dismiss(mctc);
-       }
-    } else if (mctc != NULL)
-        mctelem_dismiss(mctc);
-}
-
 /* MCA */
 
 static int mce_is_broadcast(struct cpuinfo_x86 *c)
index ab5fd1555646f3096c9e5627bfbe6d31c86dac9b..2e150bc05bc4ef960ea36ccf85ec899258c8802a 100644 (file)
@@ -772,6 +772,21 @@ void set_direct_apic_vector(
     direct_apic_vector[vector] = handler;
 }
 
+void alloc_direct_apic_vector(
+    uint8_t *vector, void (*handler)(struct cpu_user_regs *))
+{
+    static uint8_t next = LAST_HIPRIORITY_VECTOR;
+    static DEFINE_SPINLOCK(lock);
+
+    spin_lock(&lock);
+    if (*vector == 0) {
+        BUG_ON(next == FIRST_HIPRIORITY_VECTOR);
+        set_direct_apic_vector(next, handler);
+        *vector = next--;
+    }
+    spin_unlock(&lock);
+}
+
 void do_IRQ(struct cpu_user_regs *regs)
 {
     struct irqaction *action;
index b5b0f4d1258a7a3f2018750968f9f6437042032c..396f7ded826f5514226ebf550fd63151abc6c036 100644 (file)
@@ -86,12 +86,12 @@ void apic_timer_interrupt(struct cpu_user_regs *regs);
 void error_interrupt(struct cpu_user_regs *regs);
 void pmu_apic_interrupt(struct cpu_user_regs *regs);
 void spurious_interrupt(struct cpu_user_regs *regs);
-void thermal_interrupt(struct cpu_user_regs *regs);
-void cmci_interrupt(struct cpu_user_regs *regs);
 void irq_move_cleanup_interrupt(struct cpu_user_regs *regs);
 
 void set_direct_apic_vector(
     uint8_t vector, void (*handler)(struct cpu_user_regs *));
+void alloc_direct_apic_vector(
+    uint8_t *vector, void (*handler)(struct cpu_user_regs *));
 
 void do_IRQ(struct cpu_user_regs *regs);
 
index 8453d06714e4ae243ec1f7b6865c40d29e98f495..6b9cde66d1720c98bea03029f611d8801dfca363 100644 (file)
@@ -7,16 +7,14 @@
 #define INVALIDATE_TLB_VECTOR  0xfd
 #define EVENT_CHECK_VECTOR     0xfc
 #define CALL_FUNCTION_VECTOR   0xfb
-#define THERMAL_APIC_VECTOR    0xfa
-#define LOCAL_TIMER_VECTOR     0xf9
-#define PMU_APIC_VECTOR        0xf8
-#define CMCI_APIC_VECTOR       0xf7
+#define LOCAL_TIMER_VECTOR     0xfa
+#define PMU_APIC_VECTOR        0xf9
 /*
  * High-priority dynamically-allocated vectors. For interrupts that
  * must be higher priority than any guest-bound interrupt.
  */
 #define FIRST_HIPRIORITY_VECTOR        0xf0
-#define LAST_HIPRIORITY_VECTOR  0xf6
+#define LAST_HIPRIORITY_VECTOR  0xf8
 
 /* Legacy PIC uses vectors 0xe0-0xef. */
 #define FIRST_LEGACY_VECTOR    0xe0